/*  Novelties: A visual novel programming language based on JavaFX
    Copyright (C) 2008  Hao Xu
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * /
 /*
 * Scence.fx
 *
 * Created on Apr 7, 2008, 5:57:26 PM
 */

package avgengine.script;
import avgengine.*;
import avgengine.map.*;
import javafx.ui.canvas.*;
import javafx.ui.*;
import java.awt.Font;

/**
 * @author ertri
 */

class Scene {
    attribute stage: Stage;
    attribute bg : Actor;
    attribute defaultStyle : GenericParagraph;
    attribute actors: Actor*;
    attribute actorNames: String*;
    attribute mapSprites: MapSprite*;
    attribute sp: Node;
    attribute dialog: Dialog;
    attribute control: Control;
    attribute init : boolean;
    attribute pos:Position*;
    attribute metrics:TextMetrics;
    attribute click:ButtonParagraph;
    attribute map: Map;
    
    operation initialize();
    
    operation getPos(pName:String):Position;
    operation getActor(aName:String):Actor;
    
    operation selectBackground(exp:String);
    operation selectInitialBackground(exp:String);
    
    operation selectMap(exp:String);
    operation selectInitialMap(exp:String);
    
    operation actorShowsOnMap(n:String, x:int, y:int);
    operation actorMovesOnMap(n:String, x:int, y:int);
    operation actorHidesOnMap(n:String);
    operation actorEnters(n:String, side:int, p:String, exp:String);
    operation actorChanges(n:String, p:String, exp:String);
    operation actorExits(n:String, side:int);
    operation actorSays(n:String, p:String);
    operation choose(options:String*, callback:operation(i:int));
    operation waitForClick(callback:operation(e:CanvasMouseEvent):boolean,cont:operation());
}

attribute Scene.init = false;


operation Scene.getPos(pName) {
    for(p in pos) {
        if (p.name==pName) {
            return p;
        }
    }
    return null;
}

operation Scene.initialize() {
    var comp : Node* = [stage];
    
    bg.setStage(stage);
    insert bg.sp into comp;
    
    map.setStage(stage);
    insert map.sp into comp;
    
    for(a in actors) {
        a.setStage(stage);
        a.map = map;
        insert a.sp into comp;
    }
    insert dialog into comp;
    insert control into comp;
    sp = Group {
        content:comp
    };
    insert Position{x:stage.dwidth/2,name:"center"} into pos;
    metrics = new TextMetrics(3,dialog.dwidth-dialog.pad[0]*2);
    if(click <> null) {
        println("click");
        control.addButton(click);
        click.disable();
    }
    this.init = true;
    
    
}

operation Scene.getActor(n:String):Actor {
    for(i in [0..sizeof actorNames-1]) {
        if (actorNames[i]==n) {
            return actors[i];
        }
    }
    return null;
    
}
operation Scene.selectInitialBackground(exp:String) {
    this.bg.fadeInAs(exp, getPos("center"));
}
operation Scene.selectBackground(exp:String) {
    println("select background: {exp}");
    this.bg.change(exp);
}

operation Scene.selectInitialMap(exp:String) {
    this.map.fadeInAs(exp, Position{x:0});
}
operation Scene.selectMap(exp:String) {
    println("select map: {exp}");
    this.map.change(exp);
}
operation Scene.actorEnters(n:String, side:int, p:String, expr:String) {
    var actor = this.getActor(n);
    var pos = this.getPos(p);
    println("Scene.actorEnters:{n},{side},{expr},{p}");
    if(expr<>null) {
        actor.enterAs(expr,side,pos);
    } else {
        actor.enter(side,pos);
    }
}
operation Scene.actorChanges(n:String, p:String, exp:String) {
    var actor = this.getActor(n);
    var pos = this.getPos(p);
    if(p<>null) {
        actor.move(pos);
    }
    if(exp<>null) {
        actor.change(exp);
    }
}

operation Scene.actorExits(n:String, side:int) {
    var actor = this.getActor(n);
    actor.exit(side);
}
operation Scene.actorShowsOnMap(n:String, x:int, y:int) {
    var actor = this.getActor(n);
    println("Scene.actorShowsOnMap:{n},{x},{y}");
    actor.show(x,y);
}
operation Scene.actorMovesOnMap(n:String, x:int, y:int) {
    var actor = this.getActor(n);
    actor.moveOnMap(x, y);
}

operation Scene.actorHidesMap(n:String) {
    var actor = this.getActor(n);
    actor.hide();
}
operation Scene.actorSays(n:String, p:String) {
    var para =Paragraph{text:p, height:20};
    para.applyStyle(this.defaultStyle);
    var actor = this.getActor(n);
    para.applyStyle(actor.style);
    metrics.appendText(para.font.getFont(),n,p);
    para.text = metrics.getFullPage();
    metrics.reset();
    dialog.replaceText(para);
    if(metrics.hasMore()) {
        var callback = operation(e:CanvasMouseEvent):boolean {
            
            
            para.text = metrics.getFullPage();
            
            if(not metrics.hasMore()) {
                return false;
            }
            return true;
            
            
            
        };
        var cont = operation() {
            metrics.reset();
            para.applyStyle(this.defaultStyle);
            para.applyStyle(actor.style);
            dialog.replaceText(para);
        };
        waitForClick(callback, cont);
    }
}
operation Scene.waitForClick(callback:operation(e:CanvasMouseEvent):boolean,cont:operation()) {
    var old = dialog.onMouseClicked;
    click.enable();
    dialog.onMouseClicked = operation(e:CanvasMouseEvent) {
        if(callback(e)){
        } else{
            click.disable();
            dialog.onMouseClicked = old;
        }
        cont();
        //old(e);
    };
    //    println("Scene.waitForClick: {dialog.onMouseClicked}");
}

operation Scene.choose(options:String*, callback:operation(i:int)) {
    var para = OptionParagraph{
        options:options,
        height:20,
        callback: operation(i:int) {
            println("choice: {i}");
            dialog.clearText();
            callback(i);
        },
        highlight:Dialog{
            opacity:0.3,
            dwidth:100,
            pad:[5,5],
            background:blue,
            borderWidth:0,
            borderColor:blue
            
        }
    };
    para.applyStyle(this.defaultStyle);
    dialog.appendText(para);
}

